﻿#pragma strict

var minForce = 1.0;//最小力
var multiplier = 0.1;//乘数
var deformRadius = 0.3;//变形半径
var deformNoise = 0.03;//形变的不规则凹凸数
var deformNodeRadius = 0.5;//畸形足
var maxDeform = 0.35;//最大变形
var maxNodeRotationStep = 5.0;//车轮点的最大位移
var maxNodeRotation = 14.0;//最大旋转运动
var bounceBackSpeed = 0.5;//回弹速度
var bounceBackSleepCap = 0.002;//恢复原形覆盖
var autoBounce = false;//自动恢复

var DeformMeshes : MeshFilter[];//汽车车身的网格过滤器
var DeformNodes : Transform[];//汽车轮胎的位置
var DeformColliders : MeshCollider[];//汽车车身的碰撞体


class VertexData extends System.Object //顶点数据的保存
	{
	var permaVerts : Vector3[];
	}
	
private var m_meshData : VertexData[];//网状数据
private var m_colliderData : VertexData[];//碰撞数据
	
private var m_permaNodes : Vector3[];//保存车轮位置信息
private var m_permaNodeAngles : Vector3[];//保存车轮角度信息
private var m_nodeModified : boolean[];//保存车轮是否形变

private var m_sleep = true;   //判断车完全恢复的状态
private var m_doBounce = false;//是否做形变的恢复


function Start ()
	{
	//获取网格过滤器的所有顶点坐标数据
	m_meshData = new VertexData[DeformMeshes.length];//网状数据
	
	for (var i=0; i<DeformMeshes.length; i++)
		{
		m_meshData[i] = new VertexData();
		m_meshData[i].permaVerts = DeformMeshes[i].mesh.vertices;
		}
	//获得网格碰撞体的所有顶点	
	m_colliderData = new VertexData[DeformColliders.length];//碰撞数据
	
	for (i=0; i<DeformColliders.length; i++)
		{
		m_colliderData[i] = new VertexData();//碰撞数据
		m_colliderData[i].permaVerts = DeformColliders[i].sharedMesh.vertices;
		}	
		
	// 获得每个轮胎相对于车身的欧拉角
	
	m_permaNodes = new Vector3[DeformNodes.length];//保存车轮位置信息
	m_permaNodeAngles = new Vector3[DeformNodes.length];//保存车轮角度信息
	m_nodeModified = new boolean[DeformNodes.length];//保存车轮是否形变
	
	for (i=0; i<DeformNodes.length; i++)//变形节点
		{
		m_permaNodes[i] = DeformNodes[i].localPosition;
		m_permaNodeAngles[i] = AnglesToVector(DeformNodes[i].localEulerAngles);
		}
	}

 //碰撞的变形
private function DeformMesh(mesh : Mesh, originalMesh : Vector3[], localTransform : Transform, contactPoints : ContactPoint[], contactForce : Vector3)
	{
	var vertices = mesh.vertices;//顶点
	
	for (var contact in contactPoints)//对每个碰撞点进行计算确认产生形变的位置并进行形变
		{			
		if (typeof(contact.thisCollider) == WheelCollider) continue;//如果碰撞点是车轮碰撞体就跳出进行下一次计算
		var contactPoint = localTransform.InverseTransformPoint(contact.point);
		
		for (var i=0; i<vertices.length; i++)
			{
			var dist = (contactPoint-vertices[i]).magnitude;//计算碰撞点与所有网格顶点之间的距离
				
			if (dist < deformRadius)//如果距离小于变形半径则基于碰撞力产生形变
				{
				vertices[i] += (contactForce * (deformRadius - dist) / deformRadius) + Random.onUnitSphere * deformNoise;
					
				var deform = vertices[i]-originalMesh[i];
				if (deform.magnitude > maxDeform)
					vertices[i] = originalMesh[i] + deform.normalized * maxDeform;
				}
			}
		}
	mesh.vertices = vertices;//顶点
	mesh.RecalculateNormals();//重新计算网格的法线
	mesh.RecalculateBounds();//重新计算从网格包围体的顶点
	}

	
// 对轮胎周围的形变方向以及角度进行修改，返回一个bool值
private function DeformNode(T : Transform, originalLocalPos : Vector3, originalLocalRot : Vector3, contactPoint : Vector3, contactVector : Vector3) : boolean	
{
	var result = false;	
	var localPos = transform.InverseTransformPoint(T.position);//转换成局部坐标系
	
	var dist = (contactPoint-localPos).magnitude;
	
	// 对轮胎进行形变，如果产生形变大于轮胎形变的范围，基于最大值进行形变
	
	if (dist < deformRadius)//变形半径小于最小半径
		{
		var deformForce = (deformRadius - dist) / deformRadius;//形变力的比值
		
		T.localPosition += contactVector * deformForce + Random.onUnitSphere * deformNoise;
		
		var deform = T.localPosition - originalLocalPos;
		
		if (deform.magnitude > maxDeform)
			T.localPosition = originalLocalPos + deform.normalized * maxDeform;
		
		result = true;
		}
		
	// 如果碰撞点的距离最小点半径，对轮胎的旋转的角度进行调整
		
	if (dist < deformNodeRadius)//小于最小点半径
		{
		var angles = AnglesToVector(T.localEulerAngles);
		
		var angleLimit = Vector3(maxNodeRotation, maxNodeRotation, maxNodeRotation);		
		var angleMax = angles + angleLimit;
		var angleMin = angles - angleLimit;
		
		angles += deformForce * Random.onUnitSphere * maxNodeRotationStep;
				
		T.localEulerAngles = Vector3(Mathf.Clamp(angles.x, angleMin.x, angleMax.x), Mathf.Clamp(angles.y, angleMin.y, angleMax.y), Mathf.Clamp(angles.z, angleMin.z, angleMax.z));
		
		result = true;		
		}
		
	return result;
	}


// 对于车身的缓慢恢复，基于向量的加计算与原形每个点向量的对比如果达到最低返回值，返回一个bool值控制原形覆盖
private function BounceMesh(mesh : Mesh, originalMesh : Vector3[], bounceDelta : float)	: boolean//蹦极运动
	{ //                 网格过滤器    网格位置 		  每秒的回弹速度
	var result = true;	
	var vertices = mesh.vertices;//顶点
	
	for (var i=0;i<vertices.length; i++) 
		{
		var deform = originalMesh[i] - vertices[i];
		
		vertices[i] += deform * bounceDelta; 
		if (deform.magnitude >= bounceBackSleepCap)
			result = false;
		}
		
	mesh.vertices = vertices;
	mesh.RecalculateNormals();
	mesh.RecalculateBounds();
	
	return result;
	}
	

// 对于车轮点周围的缓慢恢复，基于向量的加计算与原形每个点向量的对比如果达到最低返回值，返回一个bool值控制原形覆盖
private function BounceNode(T : Transform, originalLocalPos : Vector3, originalLocalAngles : Vector3, bounceDelta : float) : boolean
	{
	// 计算原形向量与现在凹凸的差距
	
	var deformPos = originalLocalPos - T.localPosition;
	T.localPosition += deformPos * bounceDelta;
	
	// 对角度和凹凸进行恢复

	var Angles = AnglesToVector(T.localEulerAngles);
	var deformAngle = originalLocalAngles - Angles;
	Angles += deformAngle * bounceDelta;	
	T.localEulerAngles = Angles;
	
	// 对恢复状态的判断，接近最小恢复值后进行覆盖
	
	return deformPos.magnitude < bounceBackSleepCap && deformAngle.magnitude < (bounceBackSleepCap * 2); 
	}

	//恢复未碰撞状态
private function RestoreNode(T : Transform, originalLocalPos : Vector3, originalLocalAngles : Vector3)
	{
	T.localPosition = originalLocalPos;
	T.localEulerAngles = originalLocalAngles;
	}
	
	//角向量
private function AnglesToVector(Angles : Vector3) : Vector3
	{
	if (Angles.x > 180) Angles.x = -360+Angles.x;
	if (Angles.y > 180) Angles.y = -360+Angles.y;
	if (Angles.z > 180) Angles.z = -360+Angles.z;
	return Angles;
	}

	
	
private function RestoreColliders()//恢复碰撞体
	{
	if (DeformColliders.length > 0)
		{
		var CoM = GetComponent.<Rigidbody>().centerOfMass;
		for (var i=0; i<DeformColliders.length; i++)
			{
			//需要一个网格存放当前数据。
			
			var mesh : Mesh = new Mesh();//网格
			mesh.vertices = m_colliderData[i].permaVerts;
			mesh.triangles = DeformColliders[i].sharedMesh.triangles;
			mesh.RecalculateNormals();//重新计算网格的法线
			mesh.RecalculateBounds();//重新计算从网格包围体的顶点
			
			DeformColliders[i].sharedMesh = mesh;
			}
		
		GetComponent.<Rigidbody>().centerOfMass = CoM;			
		}
	}
	
	
//------------------------------碰撞形变检测--------------------------------
function OnCollisionEnter (collision : Collision)
	{
	if (collision.relativeVelocity.magnitude >= minForce)//两个碰撞物体的相对线性速度
		{
		m_sleep = false;
		//计算碰撞力度大小 （基于两个车的碰撞点的相对速度的百分之一进行凹凸计算，不知道实际的效果为多少）
		var contactForce = transform.InverseTransformDirection(collision.relativeVelocity) * multiplier * 0.1;
		// 对网格过滤器形变计算
		for (var i=0; i<DeformMeshes.length; i++)	
			DeformMesh(DeformMeshes[i].mesh, m_meshData[i].permaVerts, DeformMeshes[i].transform, collision.contacts, contactForce);
			
		// 对于网格碰撞体进行计算凹凸

		if (DeformColliders.length > 0)
			{
			var CoM = GetComponent.<Rigidbody>().centerOfMass;//获得轮胎的重心
			for (i=0; i<DeformColliders.length; i++)
				{			
				var mesh : Mesh = new Mesh();//网格
				mesh.vertices = DeformColliders[i].sharedMesh.vertices;//获取顶点列表
				mesh.triangles = DeformColliders[i].sharedMesh.triangles;//获取三角形个数
				//对于车的网格碰撞体进行碰撞凹凸计算
				DeformMesh(mesh, m_colliderData[i].permaVerts, DeformColliders[i].transform, collision.contacts, contactForce);				
				DeformColliders[i].sharedMesh = mesh;
				}
				
			GetComponent.<Rigidbody>().centerOfMass = CoM;
			}

		//保证轮胎周围点的形变
		for (i=0; i<DeformNodes.length; i++)
			m_nodeModified[i] = false;
		for (var c=0; c<collision.contacts.length; c++)
			{
			if (typeof(collision.contacts[c].thisCollider) == WheelCollider) continue;
			var contactPoint = transform.InverseTransformPoint(collision.contacts[c].point);
			for (i=0; i<DeformNodes.length; i++)
				if (!m_nodeModified[i]) m_nodeModified[i] = DeformNode(DeformNodes[i], m_permaNodes[i], m_permaNodeAngles[i], contactPoint, contactForce);
			}
		}
	}
	
//--------------------------------------------------------------

function DoBounce ()
	{
	m_doBounce = true;
	m_sleep = false;
	}
	


//--------------------------------------------------------------
function Update () 
	{
	if (!m_sleep && (autoBounce || m_doBounce) && bounceBackSpeed > 0) 
		{
		var deformDelta = Time.deltaTime * bounceBackSpeed;
		
		m_sleep = true;
		
		//按照弹性恢复速度缓慢恢复网格碰撞体
		
		for (var i=0; i<DeformMeshes.length; i++)
			m_sleep &= BounceMesh(DeformMeshes[i].mesh, m_meshData[i].permaVerts, deformDelta);

		// 按照弹性恢复速度缓慢恢复特定点

		for (i=0; i<DeformNodes.length; i++)
			m_sleep &= BounceNode(DeformNodes[i], m_permaNodes[i], m_permaNodeAngles[i], deformDelta);
		//上面两种弹性恢复都是在向量上缓慢恢复并与原保存数据对比，当误差小于最小恢复误差直接全部恢复为原状态	
		if (m_sleep)
			{
			m_doBounce = false;
			
			//精确的恢复碰撞点的状态
			for (i=0; i<DeformNodes.length; i++)
				RestoreNode(DeformNodes[i], m_permaNodes[i], m_permaNodeAngles[i]);
				
			//精确的恢复碰撞体状态
			RestoreColliders();
			}			
		}
	}

